///> ADC 从采样

#include "adc.hpp"
#include "dma.hpp"

using namespace device;

#define ADC_CONFIG_SSTR		100

static void DmaCompleteCallBack1(void);
static void DmaCompleteCallBack2(void);

typedef struct
{
	M4_ADC_TypeDef *mInstance;
	uint16_t tTrigEvtId;
	uint16_t tEvtId;
	void (*CallBack)(void);
}AdcPartitionTPDF;

typedef struct
{
	adc *pTag;
	uint8_t *pChannelLen;
	uint32_t *uiAos;
	uint32_t uiDmaHandle;
}AdcCreatedTPDF;

const AdcPartitionTPDF mAdcPartition[] = 
{
	{M4_ADC1,	EVT_TMR61_GCMA,	EVT_ADC1_EOCA,	DmaCompleteCallBack1},
	{M4_ADC2,	EVT_TMR02_GCMA,	EVT_ADC2_EOCA,	DmaCompleteCallBack2},
};

AdcCreatedTPDF mAdcCreated[] = 
{
	{0,0,(uint32_t *)&M4_AOS->ADC1_ITRGSELR0,	0},
	{0,0,(uint32_t *)&M4_AOS->ADC2_ITRGSELR0,	0},
};

static void EnableTimer(uint8_t ucIndex, uint16_t Freq)
{
	const uint32_t uiT6DivTbl[] = {1, 2, 4, 8, 16, 64, 256, 1024};
	uint32_t clk;
	uint8_t div;

	switch(ucIndex)
	{
		case 1:
			clk = ClockFreqGet(CLOCK_TYPE_APB1);	
			M4_TMR02->BCONR &= 0xFFFF0000ul;
			while(M4_TMR02->BCONR & 0x0000fffful);
			M4_TMR02->BCONR_f.SYNCLKA = 0;
			for(div = 0; div < 11; div++)
			{
				if((clk >> div) < (65535 * Freq))
				{
					break;
				}
			}
			M4_TMR02->BCONR_f.CKDIVA = div;
			M4_TMR02->CMPAR = ((clk >> div) / Freq) - 1;
			M4_TMR02->BCONR_f.SYNSA = 0;
			M4_TMR02->BCONR_f.INTENA = 1;
			M4_TMR02->BCONR_f.CSTA = 1;
			break;
		case 0:
			clk = ClockFreqGet(CLOCK_TYPE_APB0);
			for(div = 0; div < 8; div++)
			{
				if((clk / uiT6DivTbl[div]) < (65535 * Freq))
				{
					break;
				}
			}
			M4_TMR61->GCONR_f.MODE = 0;
      M4_TMR61->GCONR_f.DIR = 1;
      M4_TMR61->GCONR_f.CKDIV = div;
			M4_TMR61->PERAR = ((clk >> div) / Freq) - 1;
			M4_TMR61->GCMAR = M4_TMR61->PERAR;
			M4_TMR61->ICONR_f.INTENA = 1;	
			M4_TMR61->GCONR_f.START = 1;
			break;
	}
}
static void DisableTimer(uint8_t ucIndex)
{
	switch(ucIndex)
	{
		case 1:
			M4_TMR02->BCONR_f.CSTA = 0;
			break;
		case 0:
			M4_TMR61->GCONR_f.START = 0;
			break;
	}
}

static void DmaCompleteCallBack1(void)
{
	dma::StartDmaFsrToMem(mAdcCreated[0].uiDmaHandle, mAdcCreated[0].pTag->SampleLen,  mAdcCreated[0].pTag->Buff);
	if(!mAdcCreated[0].pTag)
	{
		return;
	}
	if(!mAdcCreated[0].pTag->ConvertCompleteCallBack)
	{
		return;
	}
	mAdcCreated[0].pTag->ConvertCompleteCallBack(mAdcCreated[0].pTag->Buff, mAdcCreated[0].pTag->SampleLen * (*mAdcCreated[0].pChannelLen));
}

static void DmaCompleteCallBack2(void)
{
	dma::StartDmaFsrToMem(mAdcCreated[1].uiDmaHandle, mAdcCreated[1].pTag->SampleLen,  mAdcCreated[1].pTag->Buff);
	if(!mAdcCreated[1].pTag)
	{
		return;
	}
	if(!mAdcCreated[1].pTag->ConvertCompleteCallBack)
	{
		return;
	}
	mAdcCreated[1].pTag->ConvertCompleteCallBack(mAdcCreated[1].pTag->Buff, mAdcCreated[1].pTag->SampleLen * (*mAdcCreated[1].pChannelLen));
}
///> 构造ADC 绑定DMA
adc::adc(AdcInstanceTPDF tInstance)
{
	dma::DmaInitTPDF dmainit;
	
	if(((uint8_t)tInstance) > 1)
	{
		return;
	}
	mInstance = 0;
	mAdcChannelLen = 0;
	Channel = 0;
	Frequnce = 0;
	SampleLen = 0;
	ConvertCompleteCallBack = 0;
	Buff = 0;
	CurrentIndex = 0;
	mAdcSemaphore = new systemos::semaphore();
	mAdcSemaphore->Take(portMAX_DELAY);
	
	dmainit.bCircularMode = false;
	dmainit.tDmaCompleteCallback = mAdcPartition[tInstance].CallBack;
	dmainit.tDmaDataType = dma::DMA_DATA_TYPE_UINT16;
	dmainit.tDmaTransMode = dma::DMA_TRANS_MODE_SFRSQR_TO_MEM;
	dmainit.uiSrc = (uint32_t)&mAdcPartition[tInstance].mInstance->DR0;
	dmainit.usSfrId = mAdcPartition[tInstance].tEvtId;
	mDmaHandle = dma::Request(&dmainit);
	if(!mDmaHandle)
	{
		mAdcSemaphore->Give();
		return;
	}
	mAdcPartition[tInstance].mInstance->STR = 0;
  mAdcPartition[tInstance].mInstance->CR0_f.ACCSEL  = 0;
	mAdcPartition[tInstance].mInstance->CR0_f.DFMT    = 0;
	mAdcPartition[tInstance].mInstance->CR0_f.CLREN   = 1;
	mAdcPartition[tInstance].mInstance->CR0_f.MS      = 0;
	mAdcPartition[tInstance].mInstance->ICR = 0;
	mAdcPartition[tInstance].mInstance->TRGSR_f.TRGSELA = 1;
	mAdcPartition[tInstance].mInstance->TRGSR_f.TRGENA = 1;
	*mAdcCreated[tInstance].uiAos = mAdcPartition[tInstance].tTrigEvtId;///触发源
	
	mAdcCreated[tInstance].pChannelLen = &mAdcChannelLen;
	mAdcCreated[tInstance].pTag = this;    ///> ADC 实例化本体
	mAdcCreated[tInstance].uiDmaHandle = mDmaHandle;
	
	mInstance = mAdcPartition[tInstance].mInstance;
	mAdcInstance = tInstance;
	
	mAdcSemaphore->Give();
}

adc::~adc(void)
{
	Stop();
	mAdcCreated[mAdcInstance].pTag = 0;						///<注销实例化对象
}

bool adc::Start(void)
{
	volatile uint32_t i, j;
	uint8_t *ucSstr = (uint8_t *)&mInstance->SSTR0;
	
	if(!Channel || !SampleLen || !Buff || !mInstance)
	{
		return(false);
	}
	CurrentIndex = 0;
	if(!Frequnce)
	{
		Frequnce = 1000;
	}
	mInstance->CHMUXR0 = 0;
	mInstance->CHMUXR1 = 0;
	mInstance->CHMUXR2 = 0;
	mInstance->CHMUXR3 = 0;
	j = 0;
	for(i = 0; i < 16; i++)
	{
		if(Channel & (1 << i))
		{
			ucSstr[i] = ADC_CONFIG_SSTR;
			if(j < 4)
			{
				mInstance->CHMUXR0 |= (i << ((j & 0x03) << 2));
			}
			else if(j < 8)
			{
				mInstance->CHMUXR1 |= (i << ((j & 0x03) << 2));
			}
			else if(j < 12)
			{
				mInstance->CHMUXR2 |= (i << ((j & 0x03) << 2));
			}
			else
			{
				mInstance->CHMUXR3 |= (i << ((j & 0x03) << 2));
			}
			j++;
		}
	}
	mAdcChannelLen = j;   //
	mInstance->CHSELRA0 = (1 << j) - 1;
	dma::StartDma(mDmaHandle, mAdcChannelLen * SampleLen, mAdcChannelLen * SampleLen, mAdcChannelLen, Buff); //启动DMA 搬运
	EnableTimer(mAdcInstance, Frequnce); //> 设置定时器触发
	
	return(true);
}

void adc::Stop(void)
{
	if(!mInstance)
	{
		return;
	}
	DisableTimer(mAdcInstance);
}
